#include "mouse.h"
#include "apic.h"
#include "memory.h"
#include "interrupt.h"
#include "printk.h"

st_keyboard_in_buf *g_p_mouse = NULL;
static int s_mouse_cnt = 0;     // 鼠标数据包由多个字节组成，该字段标记当前获取了多少个字节
st_mouse_packet g_mouse;    

void mouse_handler(unsigned long nr, unsigned long param, st_pt_regs *regs) {
    unsigned char x;
    x = io_in8(PORT_KB_DATA);
    color_printk(GREEN, WHITE, "(M:%02x)", x);

    if (g_p_mouse->p_head == g_p_mouse->buf + KB_BUF_SIZE) {
        g_p_mouse->p_head = g_p_mouse->buf;
    }

    *g_p_mouse->p_head = x;
    g_p_mouse->count++;
    g_p_mouse->p_head++;
}

unsigned char get_mousecode() {
    unsigned char ret = 0;

    if (g_p_mouse->count == 0) {
        while (!g_p_mouse->count) {
            NOP();
        }
    }

    if (g_p_mouse->p_tail == g_p_mouse->buf + KB_BUF_SIZE) {
        g_p_mouse->p_tail = g_p_mouse->buf;
    }

    ret = *g_p_mouse->p_tail;
    g_p_mouse->count--;
    g_p_mouse->p_tail++;

    return ret;
}

void analysis_mousecode() {
    unsigned char x = get_mousecode();

    switch (s_mouse_cnt) {
        case 0:
            s_mouse_cnt++;
            break;
        case 1:
            g_mouse.byte0 = x;
            s_mouse_cnt++;
            break;
        case 2:
            g_mouse.byte1 = (char)x;
            s_mouse_cnt++;
            break;
        case 3:
            g_mouse.byte2 = (char)x;
            s_mouse_cnt = 1;
            color_printk(RED, GREEN, "(M:%02x, X:%03d, y:%03d)\n", g_mouse.byte0, g_mouse.byte1, g_mouse.byte2);
            break;
        default:
            break;
    }
}

st_hw_int_type s_mouse_int_controller = {
    .enable = ioapic_enable,
    .disable = ioapic_disable,
    .install = ioapic_install,
    .uninstall = ioapic_uninstall,
    .ack = ioapic_edge_ack,
};

void mouse_init() {
    st_io_apic_rte_entry entry;
    unsigned long i, j;

    g_p_mouse = (st_keyboard_in_buf *)kmalloc(sizeof(st_keyboard_in_buf), 0);
    g_p_mouse->p_head = g_p_mouse->buf;
    g_p_mouse->p_tail = g_p_mouse->buf;
    g_p_mouse->count = 0;
    memset(g_p_mouse->buf, 0, KB_BUF_SIZE);

    entry.vector = 0x2c;        // 鼠标中断向量号
    entry.deliver_mode = APIC_ICR_IOAPIC_FIXED;
    entry.dest_mode = ICR_IOAPIC_DELV_PHYSICAL;
    entry.deliver_status = APIC_ICR_IOAPIC_IDLE;
    entry.polarity = APIC_IOAPIC_POLARITY_HIGH;
    entry.irr = APIC_IOAPIC_IRR_RESET;
    entry.trigger = APIC_ICR_IOAPIC_EDGE;
    entry.mask = APIC_ICR_IOAPIC_MASKED;
    entry.reserved = 0;
    
    entry.destination.physical.reserved1 = 0;
    entry.destination.physical.phy_dest = 0;
    entry.destination.physical.reserved2 = 0;

    s_mouse_cnt = 0;
    register_irq(0x2c, &entry, &mouse_handler, (unsigned long)g_p_mouse, &s_mouse_int_controller, "ps/2 mouse");

    WAIT_KB_WRITE();
    io_out8(PORT_KB_CMD, KBCMD_EN_MOUSE_INTFACE);

    for (i = 0; i < 1000; ++i) {
        for (j = 0; j < 1000; ++j) {
            NOP();
        }
    }

    WAIT_KB_WRITE();
    io_out8(PORT_KB_CMD, KBCMD_SENDTO_MOUSE);
    WAIT_KB_WRITE();
    io_out8(PORT_KB_DATA, MOUSE_ENABLE);

    for (i = 0; i < 1000; ++i) {
        for (j = 0; j < 1000; ++j) {
            NOP();
        }
    }

    WAIT_KB_WRITE();
    io_out8(PORT_KB_CMD, KBCMD_SENDTO_MOUSE);
    WAIT_KB_WRITE();
    io_out8(PORT_KB_DATA, 0xf2);
    WAIT_KB_READ();
    unsigned char mouse_id = io_in8(0x60);
    color_printk(RED, BLACK, "11111111111 mouse id: %02x\n", mouse_id);

    WAIT_KB_WRITE();
    io_out8(PORT_KB_CMD, KBCMD_WRITE_CMD);
    WAIT_KB_WRITE();
    io_out8(PORT_KB_DATA, KB_INIT_MODE);
}

void mouse_exit() {
    unregister_irq(0x2c);
    kfree((unsigned long *)g_p_mouse);
}